package com.health.trans.kit;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.health.trans.common.util.VoidFunc2;
import com.health.trans.util.BatchThreadPool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.metrics.BatchMetrics;

import javax.persistence.Table;
import java.time.Duration;
import java.util.Date;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 线程池队列监控
 *
 * @author nqlz
 */
@Slf4j
public class ThreadMonitor {

    protected static <T> String getTableName(Class<T> tClass) {
        Table table = tClass.getAnnotation(Table.class);
        return StrUtil.isNotBlank(table.catalog()) ? table.catalog() + "." + table.name() : table.name();
    }

    public static String getTime(Date startDate, Date endDate) {
        Duration stepExecutionDuration = BatchMetrics.calculateDuration(startDate, endDate);
        return BatchMetrics.formatDuration(stepExecutionDuration);
    }

    /**
     * 发送等待
     *
     * @param totalPage 总页
     * @param time      时间
     * @param f         f
     */
    protected static void sendSync(int totalPage, int index, AtomicLong time, VoidFunc2<Integer, Integer> f) {
        //检查线程池剩余队列数,将使用的资源数加等待数超过时，则等待线程空闲在执行
        if (checkQueue(totalPage - index)) {
            f.callWithRuntimeException(index, totalPage);
        }
        //等待超过1分钟,返回
        else if (time.get() > 60) {
            ExceptionUtil.wrapRuntimeAndThrow("等待超时，线程资源紧张，请稍后再试。");
        } else {
            if (time.get() < 1) {
                log.info("当前空闲队列太少，请等待。");
            }
            ThreadUtil.sleep(10, TimeUnit.SECONDS);
            time.getAndAdd(10);
            log.info("当前空闲队列太少，请等待。已等待：" + time.get() + "秒");
            sendSync(totalPage, index, time, f);
        }
    }


    /**
     * 手动检查线程池队列资源
     *
     * @param total 总计
     * @return boolean
     */
    protected static boolean checkQueue(int total) {
        ThreadPoolExecutor threadPoolExecutor = BatchThreadPool.POOL;
        int capacity = threadPoolExecutor.getQueue().remainingCapacity();
        return capacity > 10 && total <= (NumberUtil.mul(capacity, 1));
    }

}
